
#include "LocalLoggerHandler.hpp"

#include "DbusManager.hpp"
#include "LogCollection.hpp"

using LogCollector::Severity;
using LogCollector::Logger;
using LogCollector::ReturnStatus;

//! 默认的timeout，3s
static constexpr int64_t DEFAULT_CALLBACK_TIMEOUT { 3 };

LocalLoggerHandler::LocalLoggerHandler(
    const std::string& aServiceName, const std::string& aServicePath, const std::string& aServiceInterface)
: DbusContext(aServiceName, aServicePath, aServiceInterface)
{
}

bool LocalLoggerHandler::prepare()
{
    if (!registerInterfaces()) {
        return false;
    }

    if (!registerDiedWatcher()) {
        return false;
    }

    return true;
}

bool LocalLoggerHandler::reigsterClient(const std::string& aBusName, pid_t aPid, const std::string& aProcessName)
{
    if (mClients.find(aBusName) != mClients.end()) {
        SS_LOG(Severity::Level::ERROR, "%s has registered.", aBusName.c_str());
        return false;
    }

    mClients[aBusName] = std::pair(aPid, aProcessName);
    SS_LOG(Severity::Level::DEBUG, "Success to registerClient<%s>", aProcessName.c_str());

    return true;
}

bool LocalLoggerHandler::unregisterClient(const std::string& aBusName)
{
    const auto iter = mClients.find(aBusName);
    if (iter == mClients.end()) {
        SS_LOG(Severity::Level::ERROR, "%s not register.", aBusName.c_str());
        return false;
    }

    SS_LOG(Severity::Level::DEBUG,
        "Success to unregisterClient<%s>", iter->second.second.c_str());
    mClients.erase(iter);

    return true;
}

int LocalLoggerHandler::onClientChanged(sd_bus_message* aMessage, void* aUserdata, sd_bus_error* aError)
{
    const char* name { nullptr };
    const char* old_owner { nullptr };
    const char* new_owner { nullptr };
    //! 获取相关name
    auto ret = sd_bus_message_read(aMessage, "sss", &name, &old_owner, &new_owner);
    if (ret < 0) {
        SS_LOG(Severity::Level::ERROR,
            "Failed to read message in onClientChanged: %s", strerror(-ret));
        return -EINVAL;
    }

    if (old_owner && *old_owner && (!new_owner || !*new_owner)) {
        const auto dbusName = std::string(name);
        if (auto iter = mClients.find(dbusName); iter != mClients.end()) {
            SS_LOG(Severity::Level::DEBUG,
                "remove clientName=%s", iter->second.second.c_str());
            mClients.erase(iter);
        }
    }
    return sd_bus_reply_method_return(aMessage, nullptr);
}

bool LocalLoggerHandler::flushAll()
{
    std::unique_lock lock(mClientsMutex);
    if (mFlushCondition.wait_for(lock, std::chrono::seconds(DEFAULT_CALLBACK_TIMEOUT)) == std::cv_status::timeout) {
        SS_LOG(Severity::Level::WARNING, "Some processes flush log timeout");
        return false;
    }

    return true;
}

bool LocalLoggerHandler::clearAll()
{
    std::unique_lock lock(mClientsMutex);
    if (mClearCondition.wait_for(lock, std::chrono::seconds(DEFAULT_CALLBACK_TIMEOUT)) == std::cv_status::timeout) {
        SS_LOG(Severity::Level::WARNING, "Some processes clear log timeout");
        return false;
    }
    
    return true;
}

int LocalLoggerHandler::flushAllCallback(sd_bus_message* aMessage, void* aUserdata, sd_bus_error* aError)
{
    std::lock_guard lock(mClientsMutex);
    const char* processName = nullptr;
    sd_bus_message_read(aMessage, "s", &processName);
    SS_LOG(Severity::Level::DEBUG, "%s flushAllCallback", processName);

    if (++mFlushedCounts >= mClients.size()) {
        SS_LOG(Severity::Level::DEBUG, "All processes have flushed");
        mFlushCondition.notify_one();
        mFlushedCounts = 0;
    }

    return sd_bus_reply_method_return(aMessage, nullptr);
}

int LocalLoggerHandler::clearAllCallback(sd_bus_message* aMessage, void* aUserdata, sd_bus_error* aError)
{
    std::lock_guard lock(mClientsMutex);
    const char* processName = nullptr;
    sd_bus_message_read(aMessage, "s", &processName);
    SS_LOG(Severity::Level::DEBUG, "%s clearAllCallback", processName);

    if (++mClearedCounts >= mClients.size()) {
        SS_LOG(Severity::Level::DEBUG, "All processes have cleared");
        mClearCondition.notify_one();
        mClearedCounts = 0;
    }

    return sd_bus_reply_method_return(aMessage, nullptr);
}

bool LocalLoggerHandler::registerInterfaces()
{
    sd_bus_slot* slot { nullptr };
    auto slots = getSlots();

    slot = DbusManager::registerInterface("flushAllCallback", "s", "",
        this, &LocalLoggerHandler::flushAllCallback,
        getDbus(), getServicePath().c_str(), getServiceInterface().c_str()
    );
    if (!slot) {
        return false;
    }
    slots.push_back(slot);

    slot = DbusManager::registerInterface("clearAllCallback", "s", "",
        this, &LocalLoggerHandler::clearAllCallback,
        getDbus(), getServicePath().c_str(), getServiceInterface().c_str()
    );
    if (!slot) {
        return false;
    }
    slots.push_back(slot);

    return true;
}

bool LocalLoggerHandler::registerDiedWatcher()
{
    auto ret = DbusManager::matchSignal(
        "NameOwnerChanged", this, &LocalLoggerHandler::onClientChanged,
        getDbus(), "org.freedesktop.DBus", "org.freedesktop.DBus"
    );

    if (!ret) {
        SS_LOG(Severity::Level::ERROR,
            "Failed to registerDiedWatcher");
        return false;
    }

    SS_LOG(Severity::Level::DEBUG, "Successfully registerDiedWatcher.");
    
    return true;
}
